﻿package mlc.haxe.input.command;
import mlc.haxe.input.formatting.InputFormatter;

/**
 * A command that accepts one argument, and formats that argument internally.
 */
class MonadicCommand<Datatype> extends Command, implements ExecutableCommand {
	private var inputFormatter:InputFormatter<Datatype>;
	private var method:Datatype -> Void;
	/**
	 * Creates a new monadic command.
	 */
	public function new(method:Datatype -> Void, inputFormatter:InputFormatter<Datatype>, remove:String -> Bool, key:String):Void {
		super(remove, key);
		this.method = method;
		this.inputFormatter = inputFormatter;
	}
	public function execute(arguments:Array<String>, writeError:String -> Void):Void {
		if (1 == arguments.length) {
			var argument:Datatype;
			// Try to format the passed argument using the input formatter.
			try {
				argument = inputFormatter.format(arguments[0]);
			// If the argument could not be formatted, write the error back to the console and stop right away.
			} catch (error:Dynamic) {
				writeError(Std.string(error));
				return;
			}
			method(argument);
		} else {
			writeError("This command accepts exactly one argument.");
		}
	}
	public function determineEquals(value:ExecutableCommand):Bool {
		// Since the first check makes sure the type of the passed value is equal to this one, it is safe to assume that the passed
		// value has a method property in the second. However, AS3 compilers don't like this. We have to cast it explicitly for
		// them.
		#if as3
		return Std.is(value, MonadicCommand) && Reflect.compareMethods(cast(value, MonadicCommand<Dynamic>).method, method);
		#else
		return Std.is(value, MonadicCommand) && Reflect.compareMethods((untyped value).method, method);
		#end
	}
}